<?php
/**
 * 优化版数据权限控制服务
 * 添加缓存机制和查询性能优化
 */

declare(strict_types=1);

namespace app\service;

use think\facade\Db;
use think\facade\Cache;

class OptimizedDataPermissionService extends DataPermissionService
{
    /**
     * 缓存配置
     */
    private const CACHE_CONFIG = [
        'ttl' => 7200, // 缓存2小时（权限变化较少）
        'prefix' => 'permission:',
        'tags' => ['permission']
    ];

    /**
     * 缓存键名
     */
    private const CACHE_KEYS = [
        'user_info' => 'user_info:',
        'user_permissions' => 'user_permissions:',
        'access_check' => 'access_check:',
        'module_config' => 'module_config'
    ];

    /**
     * 获取用户权限信息（优化版）
     * 添加缓存机制
     */
    private function getUserPermissionInfo(int $userId): array
    {
        $cacheKey = $this->buildCacheKey(self::CACHE_KEYS['user_info'], $userId);
        $cached = Cache::get($cacheKey);
        if ($cached !== null) {
            return $cached;
        }

        // 优化查询 - 减少JOIN，使用索引
        $userInfo = Db::name('admin')
            ->alias('a')
            ->join('department d', 'a.did = d.id', 'LEFT')
            ->field('a.id, a.did, a.status, d.title as dept_name, d.parent_id')
            ->where('a.id', $userId)
            ->where('a.status', '>=', 0)
            ->find();
        
        if ($userInfo) {
            // 获取用户管理的部门层级（优化版）
            $userInfo['leader_departments'] = $this->getUserLeaderDepartments($userInfo['did'], $userInfo['id']);
            
            // 获取用户角色权限
            $userInfo['roles'] = $this->getUserRoles($userId);
        }

        $result = $userInfo ?: [];
        
        // 缓存用户信息
        $this->setCacheWithKeyTracking($cacheKey, $result, self::CACHE_CONFIG['ttl'], $userId);
        
        return $result;
    }

    /**
     * 获取用户数据权限信息（优化版）
     */
    public function getUserDataPermissions(int $userId, string $module = ''): array
    {
        $cacheKey = $this->buildCacheKey(self::CACHE_KEYS['user_permissions'], $userId, $module);
        $cached = Cache::get($cacheKey);
        if ($cached !== null) {
            return $cached;
        }

        $permissions = [];
        
        // 获取用户信息（使用缓存）
        $userInfo = $this->getUserPermissionInfo($userId);
        
        // 构建权限信息
        $permissions[] = [
            'module' => $module ?: 'all',
            'dimension' => 'personal',
            'value' => $userId,
            'description' => '个人数据权限'
        ];
        
        if (!empty($userInfo['did'])) {
            $permissions[] = [
                'module' => $module ?: 'all',
                'dimension' => 'department', 
                'value' => $userInfo['did'],
                'description' => '部门数据权限'
            ];
        }
        
        if (!empty($userInfo['leader_departments'])) {
            $permissions[] = [
                'module' => $module ?: 'all',
                'dimension' => 'leader',
                'value' => implode(',', $userInfo['leader_departments']),
                'description' => '领导数据权限'
            ];
        }

        // 角色权限
        if (!empty($userInfo['roles'])) {
            foreach ($userInfo['roles'] as $role) {
                $permissions[] = [
                    'module' => $module ?: 'all',
                    'dimension' => 'role',
                    'value' => $role['id'],
                    'description' => $role['name'] . '角色权限'
                ];
            }
        }
        
        // 缓存权限信息
        $this->setCacheWithKeyTracking($cacheKey, $permissions, self::CACHE_CONFIG['ttl'], $userId);
        
        return $permissions;
    }

    /**
     * 构建数据权限查询条件（优化版）
     * 预计算权限条件，减少运行时计算
     */
    public function buildPermissionConditions(int $userId, string $module, array $options = []): array
    {
        if ($userId <= 0) {
            throw new \Exception('用户ID不能为空');
        }

        // 超级管理员拥有所有权限
        if ($userId === 1) {
            return []; // 空条件表示无限制
        }

        // 尝试从缓存获取
        $cacheKey = $this->buildCacheKey('conditions', $userId, $module, md5(serialize($options)));
        $cached = Cache::get($cacheKey);
        if ($cached !== null) {
            return $cached;
        }

        // 获取用户信息和权限信息（使用缓存）
        $userInfo = $this->getUserPermissionInfo($userId);
        
        // 构建基础权限条件
        $conditions = [];
        
        // 1. 个人数据权限
        $personalConditions = $this->buildPersonalConditionsOptimized($userId, $module);
        
        // 2. 部门数据权限  
        $departmentConditions = $this->buildDepartmentConditionsOptimized($userInfo, $module);
        
        // 3. 角色权限
        $roleConditions = $this->buildRoleConditions($userInfo, $module);
        
        // 合并所有权限条件（使用OR逻辑）
        $allConditions = array_merge(
            $personalConditions,
            $departmentConditions,
            $roleConditions
        );
        
        // 缓存条件
        $this->setCacheWithKeyTracking($cacheKey, $allConditions, self::CACHE_CONFIG['ttl'], $userId);
        
        return $allConditions;
    }

    /**
     * 检查用户是否有数据访问权限（优化版）
     * 添加缓存和查询优化
     */
    public function checkDataAccess(int $userId, string $module, int $dataId, array $options = []): bool
    {
        if ($userId === 1) {
            return true; // 超级管理员
        }
        
        // 缓存访问检查结果
        $cacheKey = $this->buildCacheKey(self::CACHE_KEYS['access_check'], $userId, $module, $dataId);
        $cached = Cache::get($cacheKey);
        if ($cached !== null) {
            return $cached;
        }
        
        $conditions = $this->buildPermissionConditions($userId, $module, $options);
        
        if (empty($conditions)) {
            Cache::set($cacheKey, true, self::CACHE_CONFIG['ttl']);
            return true; // 无限制条件
        }
        
        // 构建查询检查数据访问权限
        $tableName = $this->getModuleTableName($module);
        
        // 使用EXISTS查询优化性能
        $hasAccess = Db::name($tableName)
            ->where('id', $dataId)
            ->where(function ($query) use ($conditions) {
                foreach ($conditions as $condition) {
                    $query->whereOr($condition);
                }
            })
            ->count() > 0;
        
        // 缓存结果（较短时间，因为数据可能会变化）
        Cache::set($cacheKey, $hasAccess, 1800); // 30分钟
        
        return $hasAccess;
    }

    /**
     * 批量检查数据访问权限
     * 优化多条数据的权限检查
     */
    public function batchCheckDataAccess(int $userId, string $module, array $dataIds): array
    {
        if ($userId === 1) {
            return array_fill_keys($dataIds, true); // 超级管理员
        }

        if (empty($dataIds)) {
            return [];
        }

        $conditions = $this->buildPermissionConditions($userId, $module);
        
        if (empty($conditions)) {
            return array_fill_keys($dataIds, true); // 无限制条件
        }

        $tableName = $this->getModuleTableName($module);
        
        // 批量查询有权限的数据ID
        $accessibleIds = Db::name($tableName)
            ->whereIn('id', $dataIds)
            ->where(function ($query) use ($conditions) {
                foreach ($conditions as $condition) {
                    $query->whereOr($condition);
                }
            })
            ->column('id');

        // 构建结果数组
        $result = [];
        foreach ($dataIds as $dataId) {
            $result[$dataId] = in_array($dataId, $accessibleIds);
        }

        return $result;
    }

    /**
     * 获取用户管理的部门层级（优化版）
     */
    private function getUserLeaderDepartments(int $deptId, int $userId): array
    {
        if (!$deptId) {
            return [];
        }

        // 这里可以实现更复杂的层级权限逻辑
        // 目前简化为用户所在部门
        return [$deptId];
    }

    /**
     * 获取用户角色
     */
    private function getUserRoles(int $userId): array
    {
        // TODO: 实现角色权限系统
        // 这里可以查询用户角色表
        return [];
    }

    /**
     * 构建个人数据权限条件（优化版）
     */
    private function buildPersonalConditionsOptimized(int $userId, string $module): array
    {
        $conditions = [];
        
        // 使用配置映射减少switch语句
        $fieldMap = [
            'customer' => 'belong_uid',
            'contract' => 'admin_id',
            'expense' => 'admin_id',
            'invoice' => 'admin_id',
            'ticket' => 'admin_id',
            'project' => 'manager_id'
        ];
        
        $field = $fieldMap[$module] ?? 'admin_id';
        $conditions[] = [$field, '=', $userId];
        
        return $conditions;
    }

    /**
     * 构建部门数据权限条件（优化版）
     */
    private function buildDepartmentConditionsOptimized(array $userInfo, string $module): array
    {
        $conditions = [];
        
        if (empty($userInfo['did'])) {
            return $conditions;
        }
        
        $departmentIds = [$userInfo['did']];
        
        // 使用配置映射
        $fieldMap = [
            'customer' => 'belong_did',
            'contract' => 'did',
            'expense' => 'did',
            'invoice' => 'did',
            'ticket' => 'did'
        ];
        
        if (isset($fieldMap[$module])) {
            $conditions[] = [$fieldMap[$module], 'in', $departmentIds];
        }
        
        return $conditions;
    }

    /**
     * 构建角色权限条件
     */
    private function buildRoleConditions(array $userInfo, string $module): array
    {
        $conditions = [];
        
        // TODO: 实现角色权限条件构建
        // if (!empty($userInfo['roles'])) {
        //     // 根据角色构建权限条件
        // }
        
        return $conditions;
    }

    /**
     * 构建缓存键
     */
    private function buildCacheKey(string $prefix, ...$params): string
    {
        return self::CACHE_CONFIG['prefix'] . $prefix . ':' . implode(':', $params);
    }

    /**
     * 设置缓存并维护缓存键列表
     */
    private function setCacheWithKeyTracking(string $key, $data, int $ttl, int $userId = null): bool
    {
        $result = Cache::set($key, $data, $ttl);
        
        if ($result && $userId) {
            // 维护用户缓存键列表
            $cacheKeysKey = 'permission_cache_keys_' . $userId;
            $userCacheKeys = Cache::get($cacheKeysKey, []);
            if (!in_array($key, $userCacheKeys)) {
                $userCacheKeys[] = $key;
                Cache::set($cacheKeysKey, $userCacheKeys, $ttl);
            }
        }
        
        return $result;
    }

    /**
     * 清理用户权限缓存
     */
    public function clearUserPermissionCache(int $userId): void
    {
        // 直接删除具体的缓存键
        $exactKeys = [
            self::CACHE_CONFIG['prefix'] . self::CACHE_KEYS['user_info'] . $userId
        ];
        
        foreach ($exactKeys as $key) {
            Cache::delete($key);
        }
        
        // 对于模式匹配的缓存，由于 ThinkPHP Cache::clear() 不支持参数
        // 我们需要使用标签清理或者维护缓存键列表的方式
        // 这里暂时使用清理所有权限缓存的方式（可以优化为使用缓存标签）
        if (Cache::has('permission_cache_keys_' . $userId)) {
            $userCacheKeys = Cache::get('permission_cache_keys_' . $userId, []);
            foreach ($userCacheKeys as $key) {
                Cache::delete($key);
            }
            Cache::delete('permission_cache_keys_' . $userId);
        }
    }

    /**
     * 清理模块权限缓存
     */
    public function clearModulePermissionCache(string $module): void
    {
        // 由于 ThinkPHP Cache::clear() 不支持模式匹配
        // 这里使用缓存标签清理方式
        if (method_exists(Cache::class, 'tag')) {
            Cache::tag(['permission', 'module_' . $module])->clear();
        } else {
            // 如果不支持标签，记录日志并跳过
            \think\facade\Log::warning('模块缓存清理跳过，不支持模式匹配: ' . $module);
        }
    }

    /**
     * 预热权限缓存
     * 为活跃用户预加载权限信息
     */
    public function warmupPermissionCache(array $userIds): void
    {
        foreach ($userIds as $userId) {
            // 预加载用户信息
            $this->getUserPermissionInfo($userId);
            
            // 预加载常用模块权限
            $commonModules = ['customer', 'contract', 'expense', 'invoice', 'project'];
            foreach ($commonModules as $module) {
                $this->getUserDataPermissions($userId, $module);
                $this->buildPermissionConditions($userId, $module);
            }
        }
    }

    /**
     * 获取模块对应的表名（优化版）
     * 重写父类的私有方法以便在子类中使用
     */
    private function getModuleTableName(string $module): string
    {
        $tableMapping = [
            'customer' => 'customer',
            'contract' => 'contract',
            'expense' => 'expense',
            'invoice' => 'invoice',
            'ticket' => 'ticket',
            'project' => 'project',
            'lawcase' => 'lawcase',
            'task' => 'project_task',
        ];
        
        return $tableMapping[$module] ?? $module;
    }
}